using System;
using System.Collections;
using SecuBat.Crawling;
using SecuBat.Notification;
using Css.Diagnostics;
using SecuBat.Logging;

namespace SecuBat.Work
{
	/// <summary>
	/// Summary description for NotificateAboutVulnerabilityTask.
	/// </summary>
	public class NotificateAboutVulnerabilityTask : Task
	{
		private int _notificationRunId;
		private int _attackId;
		private WebAddress _address;
		private String _mailBodyTemplate;
		private String _mailSubjectTemplate;
		private String _recipients;
		private bool _useServiceX;
		private bool _useSmartWhoIs;

		// TODO: add locking
		public WebAddress WebAddress
		{
			get { return _address; }
			set { _address = value; }
		}

		public String Recipients
		{
			get { return LockedCopy(ref _recipients); }
			set { LockedSet(ref _recipients, ref value); }
		}

		public NotificateAboutVulnerabilityTask(int notificationRunId, int attackId, WebAddress address, DateTime attackTime, bool useServiceX, bool useSmartWhoIs, String mailSubjectTemplate, String mailBodyTemplate)
		{
			_notificationRunId = notificationRunId;
			_attackId = attackId;
			_address = address;
			_useServiceX = useServiceX;
			_useSmartWhoIs = useSmartWhoIs;
			_mailBodyTemplate = mailBodyTemplate;
			_mailSubjectTemplate = mailSubjectTemplate;
            this.Url = address.Url;
		}

		public override void Run()
		{
            this.Status = TaskStatus.Initializing;
            this.TaskActivity = "Initializing notification";
            this.SignalizeStatusChange();
            base.Run();
			
			try
			{
				// Get Mailaddresses from whois
				String domain = this._address.HostName;
				domain = domain.ToLower();
				if (domain.StartsWith("www."))
					domain = domain.Substring(4);
				LogManager.Write(TraceLevel.Information, "Getting recipients for domain " + domain + ".", "Notification");
				String lastCheckedDomain = domain;

                this.Status = TaskStatus.SendingRequest;
                this.TaskActivity = "Requesting mail addresses";
                this.SignalizeStatusChange();
                ArrayList possibleRecipients = DnsQuery.GetMailadresses(domain, _useServiceX, _useSmartWhoIs, out lastCheckedDomain);

                this.Status = TaskStatus.AnalyzingResponse;
                this.TaskActivity = "Analyzing mail addresses";
                this.SignalizeStatusChange();

				// Look for domain mail addresses
				ArrayList useRecipients = new ArrayList();
				foreach (String address in possibleRecipients)
				{
					if (address.ToLower().EndsWith(domain))
						useRecipients.Add(address);
				}
				if (useRecipients.Count < 1)
					useRecipients = possibleRecipients;

				// Build recipient string
				_recipients = "";
				foreach (String address in useRecipients)
				{
					_recipients += address + ";";
				}

				if (_recipients.Length < 1)
				{
					_recipients = "office@" + lastCheckedDomain;
					LogManager.Write(TraceLevel.Information, "No recipients found, trying to send to " + _recipients + ".", "Notification");
				}
				else
				{
					LogManager.Write(TraceLevel.Information, "Using found recipients: " + _recipients + ".", "Notification");
				}

				// Build message
				String subject = String.Format(_mailSubjectTemplate, this._address.HostName);
				String body = String.Format(_mailBodyTemplate, this._address.HostName);

				// Send message

                this.Status = TaskStatus.SendingRequest;
                this.TaskActivity = "Sending notification";
                this.SignalizeStatusChange();

                bool success = false;
				String error = "";
				DateTime sendTime = DateTime.Now;
				try
				{
					SignedMail mail = new SignedMail(_recipients, subject, body, "Stefan Kals", "seclabpass");
					mail.Send();
					success = true;
					LogManager.Write(TraceLevel.Information, "Successfully sent mail to " + _recipients + ".", "Notification");
				}
				catch (Exception ex)
				{
					error = ex.Message;
					if (ex.InnerException != null)
						error += " - " + ex.InnerException.Message;
					LogManager.Write(TraceLevel.Error, "Error while sending mail to " + _recipients + "!", "Notification");
					LogManager.Write(TraceLevel.Error, ex, "Notification");
				}

				// Log notification
                this.Status = TaskStatus.Reporting;
                this.TaskActivity = "Reporting notification";
                this.SignalizeStatusChange();

				NotificationDbManager.NewNotification(this._notificationRunId, this._attackId, this._address.HostName, this._address.Url, this.Recipients, success, sendTime, error);
			}
			catch (Exception ex)
			{
				LogManager.Write(TraceLevel.Error, ex, "Task execution");	
			}

			this.Status = TaskStatus.Finished;
            this.SignalizeStatusChange();
		}	
	}
}
